﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Management.Automation;
using System.Management.Automation.Host;
using System.Management.Automation.Runspaces;
using System.Diagnostics;
using System.Text;
using System.Text.RegularExpressions;
using System.Security;
using System.Net;
using System.Net.NetworkInformation;
using System.Runtime.InteropServices;
using System.Xml;

namespace FIM.PS.Resources
{
    public class PowershellUtils
    {

        public Runspace OpenRunSpace(string host, string user, SecureString password, String psAuthMechanism)
        {
            string SHELL_URI = "http://schemas.microsoft.com/powershell/Microsoft.PowerShell";

            if (string.IsNullOrEmpty(host))
            {
                Runspace myRunSpace = RunspaceFactory.CreateRunspace();

                myRunSpace.Open();

                return myRunSpace;
            }
            else
            {
                //Create credential to use for authentication
                PSCredential credential = CreatePSCredential(user, password);

                //Validate Uri path
                if (!host.ToLower().EndsWith(":5985/wsman")) { host = host + ":5985/wsman"; }
                if (!(host.ToLower().StartsWith("http://") || host.StartsWith("https://"))) { host = "HTTP://" + host; }

                //Create connectionInfo
                Uri serverUri = new Uri(host);
                WSManConnectionInfo connectionInfo = new WSManConnectionInfo(serverUri, SHELL_URI, credential);
                switch (psAuthMechanism.ToLower())
                {
                    case "Default": connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Default; break;
                    case "Basic": connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Basic; break;
                    case "Credssp": connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Credssp; break;
                    case "Digest": connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Digest; break;
                    case "Kerberos": connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Kerberos; break;
                    case "Negotiate": connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Negotiate; break;
                    case "NegotiateWithImplicitCredential": connectionInfo.AuthenticationMechanism = AuthenticationMechanism.NegotiateWithImplicitCredential; break;
                    default: connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Default; break;
                }

                //Create Runspace
                Runspace myRunSpace = RunspaceFactory.CreateRunspace(connectionInfo);

                //Open Runspace
                myRunSpace.Open();

                return myRunSpace;

            }

        }

        public PSCredential CreatePSCredential(string username, SecureString password)
        {
            PSCredential credential = new PSCredential(username, password);
            return credential;
        }

        public void AddPlugins(string plugins, ref Runspace runspace)
        {
            if (!String.IsNullOrEmpty(plugins))
            {
                foreach (string plugin in plugins.Split(','))
                {
                    PowerShell myPowerShell = PowerShell.Create();
                    myPowerShell.Runspace = runspace;
                    myPowerShell.AddCommand("Add-PSSnapin");
                    myPowerShell.AddParameter("name", plugin);
                    myPowerShell.Invoke();
                    myPowerShell.Dispose();
                }
            }

        }

        public bool ExecutePowershell(PowerShell powershell, ref ICollection<PSObject> psResults, ref String errorMsg)
        {
            psResults = null;
            return ExecutePowershell(powershell, ref psResults, ref errorMsg, true);
        }

        public bool ExecutePowershell(PowerShell powershell, ref ICollection<PSObject> psResults, ref String errorMsg, bool treatWarningsAsError)
        {
            errorMsg = null;
            try
            {
                psResults = powershell.Invoke();

                //Check result
                if (powershell.Streams.Error.Count > 0)
                {
                    errorMsg = "{Error}";
                    foreach (ErrorRecord err in powershell.Streams.Error) { errorMsg += ", " + err.Exception.Message; }
                    return false;
                }
                if (powershell.Streams.Warning.Count > 0)
                {
                    errorMsg = "{Warning}";
                    foreach (WarningRecord warn in powershell.Streams.Warning) { errorMsg += ", " + warn.Message; }
                    if (treatWarningsAsError) { return false; }
                }

                powershell.Runspace.Close();
                powershell.Runspace.Dispose();

                errorMsg = null;
                return true;
            }
            catch (Exception ex)
            {
                powershell.Runspace.Close();
                powershell.Runspace.Dispose();
                errorMsg = "{Exception}, " + ex.Message;
                return false;
            }

        }

        public SecureString ConvertToSecureString(String plainString)
        {
            if (String.IsNullOrEmpty(plainString)) return null;
            char[] stringChars = plainString.ToCharArray();
            SecureString secureString = new SecureString();
            foreach (char c in stringChars) { secureString.AppendChar(c); }
            return secureString;
        }

    }

}
